package cn.backflow.secure;

import cn.backflow.secure.exception.PermissionDeniedException;
import cn.backflow.secure.exception.UnauthorizedException;
import cn.backflow.utils.JsonMap;
import cn.backflow.web.Jackson;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

/**
 * 系统全局异常处理器
 * Created by Nandy on 2016/6/23.
 */
@ControllerAdvice
public class GlobalExceptionHandler extends ExceptionHandlerExceptionResolver {
    private Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    private final MessageSource messageSource;

    @Autowired
    public GlobalExceptionHandler(MessageSource messageSource) {this.messageSource = messageSource;}

    /*
     * 捕获所有系统内部错误
     */
    @ExceptionHandler(Throwable.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, HttpServletResponse res, Exception e, Locale locale) {
        JsonMap json = new JsonMap();
        String msg = e.getLocalizedMessage();

        Throwable throwable = ExceptionUtils.getRootCause(e);
        if (throwable != null) {
            msg = throwable.getLocalizedMessage();
        }

        log.error("GlobalExceptionHandler", e);
        res.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        if (e instanceof MissingServletRequestParameterException) {
            res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            if (msg == null) {
                msg = "Missing parameter!";
            }
        }
        if (e instanceof NoHandlerFoundException) {
            res.setStatus(HttpServletResponse.SC_NOT_FOUND);
            if (msg == null) {
                msg = "Not found!";
            }
        }
        if (e instanceof PermissionDeniedException) {
            res.setStatus(HttpServletResponse.SC_FORBIDDEN);
            if (msg == null) {
                msg = "Permission denied!";
            }
        }
        if (e instanceof UnauthorizedException) {
            res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            if (msg == null) {
                msg = "Unauthorized!";
            }
        }

        json.msg(msg);
        return new ModelAndView(new MappingJackson2JsonView(Jackson.mapper), json);
    }

    @ExceptionHandler(TypeMismatchException.class)
    public ModelAndView handleArgumentNotValidException(MethodArgumentNotValidException ex, Locale locale) {
        BindingResult result = ex.getBindingResult();
        List<String> errorMessages = result.getAllErrors()
                .stream()
                .map(objectError -> messageSource.getMessage(objectError, locale))
                .collect(Collectors.toList());
        return new ModelAndView(new MappingJackson2JsonView(Jackson.mapper), "msg", errorMessages);
    }
}